<script setup>
import { getElementSize } from '@/views/study/three/composables'
import { useResizeObserver } from '@vueuse/core'
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

const webgl = ref(null)

const switchVal = ref(false)

const sliderVal = ref(0)

let renderer = null
let camera = null
let mixer = null
let clipAction = null

onMounted(() => {
  const { width, height } = getElementSize(webgl)

  const scene = new THREE.Scene()
  const clock = new THREE.Clock()
  camera = new THREE.PerspectiveCamera(30, width / height, 0.1, 1000)

  camera.position.set(5, 5, 5)

  const lights = []
  lights[0] = new THREE.DirectionalLight('#FFF', 5)
  lights[1] = new THREE.DirectionalLight('#FFF', 5)
  lights[2] = new THREE.DirectionalLight('#FFF', 5)

  lights[0].position.set(0, 100, 0)
  lights[1].position.set(50, 100, 50)
  lights[2].position.set(-50, -100, -50)

  scene.add(...lights)

  const helpers = []
  helpers[0] = new THREE.DirectionalLightHelper(lights[0], 5)
  helpers[1] = new THREE.DirectionalLightHelper(lights[1], 5)
  helpers[2] = new THREE.DirectionalLightHelper(lights[2], 5)

  scene.add(...helpers)

  const group = new THREE.Group()

  const geometry = new THREE.BoxGeometry(1, 1, 1)
  const wireframe = new THREE.WireframeGeometry(geometry)

  // 网格材质
  const meshMaterial = new THREE.MeshPhongMaterial({
    color: '#156289',
  })
  // 线材质
  const lineMaterial = new THREE.LineBasicMaterial({
    color: '#FFF',
    transparent: true,
    opacity: 0.5,
  })

  const mesh = new THREE.Mesh(geometry, meshMaterial)

  group.add(mesh)
  group.add(new THREE.LineSegments(wireframe, lineMaterial))

  scene.add(group)

  const axesHelper = new THREE.AxesHelper(5)
  scene.add(axesHelper)

  const gridHelper = new THREE.GridHelper(100, 100)
  scene.add(gridHelper)

  renderer = new THREE.WebGLRenderer({
    preserveDrawingBuffer: true,
  })
  renderer.setSize(width, height)
  renderer.render(scene, camera)
  webgl.value.appendChild(renderer.domElement)

  // 轨道控制器
  const orbit = new OrbitControls(camera, renderer.domElement)
  orbit.enableDamping = true

  mesh.name = 'Box'

  const rotKFT = new THREE.KeyframeTrack('Box.rotation[x]', [0, 6], [0, Math.PI * 2])
  // 0秒~2秒 位置从(0, 0, 0) 到 (5, 0, 0) 2秒到4秒 位置从(5, 0, 0) 到 (0, 0, 5) 4秒到6秒 位置从(0, 0, 5) 到 (0, 0, 0)
  const posKFT = new THREE.KeyframeTrack('Box.position', [0, 2, 4, 6], [0, 0, 0, 5, 0, 0, 0, 0, 5, 0, 0, 0])
  // 2秒~5秒 颜色从 rgb(1, 0, 0) 到 rgb(0, 0, 1)
  const colorKFT = new THREE.KeyframeTrack('Box.material.color', [2, 5], [1, 0, 0, 0, 0, 1])
  const clip = new THREE.AnimationClip('demo', 6, [rotKFT, posKFT, colorKFT])

  mixer = new THREE.AnimationMixer(mesh)

  clipAction = mixer.clipAction(clip)
  clipAction.paused = !switchVal.value
  // clipAction.loop = THREE.LoopOnce // 只执行一次
  // clipAction.clampWhenFinished = true // 动画将在最后一帧之后自动暂停

  function render() {
    requestAnimationFrame(render)

    // group.rotation.x += 0.005
    // group.rotation.y += 0.005

    orbit.update()

    mixer.update(clock.getDelta())

    renderer.render(scene, camera)
  }

  render()
})

function resizeHandler() {
  const { width, height } = getElementSize(webgl)

  camera.aspect = width / height
  camera.updateProjectionMatrix()

  renderer.setSize(width, height)
}

function handleSwitchChange(v) {
  if (!clipAction.isScheduled())
    clipAction.play()

  clipAction.paused = !v
}

function handleSliderChange(v) {
  if (!clipAction.isScheduled())
    clipAction.play()

  clipAction.time = v / 10
}

function handleDownload() {
  const link = document.createElement('a')

  const canvas = renderer.domElement

  link.href = canvas.toDataURL()
  link.download = 'xxx.png'

  link.click()
}

useResizeObserver(webgl, () => {
  resizeHandler()
})
</script>

<template>
  <div flex="~ col" gap="5px">
    <n-card size="small">
      <n-flex align="center">
        <n-switch v-model:value="switchVal" size="small" @update:value="handleSwitchChange">
          <template #checked>
            开始
          </template>
          <template #unchecked>
            暂停
          </template>
        </n-switch>

        <n-slider v-model:value="sliderVal" :max="60" :step="1" w="100px" @update:value="handleSliderChange" />

        <n-button size="small" @click="handleDownload">
          下载图片
        </n-button>
      </n-flex>
    </n-card>

    <div ref="webgl" flex="1" overflow="hidden" />
  </div>
</template>
